package cn.iocoder.yudao.module.scrm.strategy.strategyimpl;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.scrm.controller.admin.invoice.vo.InvoiceSaveReqVO;
import cn.iocoder.yudao.module.scrm.controller.admin.receivable.vo.ReceivableSaveReqVO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.invoice.InvoiceDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.receivable.ReceivableDO;
import cn.iocoder.yudao.module.scrm.dal.dataobject.refund.RefundDO;
import cn.iocoder.yudao.module.scrm.dal.mysql.invoice.InvoiceMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.order.OrderMapper;
import cn.iocoder.yudao.module.scrm.dal.mysql.receivable.ReceivableMapper;
import cn.iocoder.yudao.module.scrm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.scrm.strategy.CompareStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.scrm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.scrm.util.CompareUtil.getFieldValue;

/**
 * 实现了 CompareStrategy 接口，用于处理订单和发票金额比较的逻辑。
 * 主要功能包括验证发票总金额是否超过订单金额，以及计算现有发票总金额。
 *
 * @Author LiZhiMin
 * @Date 2024/9/3 12:15
 */
@Component
public class OrderInvoiceStrategyImpl implements CompareStrategy {
    @Resource
    private InvoiceMapper invoiceMapper;

    @Resource
    private OrderMapper orderMapper;

    /**
     * 处理 {@link InvoiceSaveReqVO} 类型的数据。
     * <p>
     * 获取订单信息、计算主键字段的值和外表字段的值，比较主表已存在的应收金额与新增的应收金额是否符合预期。
     * </p>
     *
     * @param request             请求对象，必须是 {@link InvoiceSaveReqVO} 类型。
     * @param foreignKeyFieldName 外部业务类型字段名称，用于标识应收表中的字段。
     * @param majorKeyFieldName   主要业务类型字段名称，用于标识订单表中的字段。
     */
    @Override
    public void handle(Object request, String foreignKeyFieldName, String majorKeyFieldName, CrmBizTypeEnum crmBizTypeEnum) {
        if (request instanceof InvoiceSaveReqVO) {
            // 处理 ReceivableSaveReqVO 类型的数据
            processSaveReqVoByType(request, foreignKeyFieldName, majorKeyFieldName);
        } else {
            throw exception(COMPARE_STRATEGY_TYPE, request.getClass().getName());
        }
    }

    /**
     * 处理 InvoiceSaveReqVO 类型的数据，进行金额比较和验证。
     *
     * @param objVo               请求对象，应为 InvoiceSaveReqVO 类型
     * @param foreignKeyFieldName 发票对象中的字段名
     * @param majorJeyFieldName   订单对象中的主要字段名
     */
    private void processSaveReqVoByType(Object objVo, String foreignKeyFieldName, String majorJeyFieldName) {
        try {
            InvoiceSaveReqVO vo = (InvoiceSaveReqVO) objVo;
            // 获取订单信息
            OrderDO orderDO = orderMapper.selectById(vo.getOrderId());

            // 计算主键字段的值
            BigDecimal foreignKeyFieldValue = getFieldValue(InvoiceSaveReqVO.class, vo, foreignKeyFieldName);

            // 计算外表字段的值-总金额
            BigDecimal totalMoneyMajorKeyFieldValue = getFieldValue(OrderDO.class, orderDO, majorJeyFieldName);

            // 计算主表已存在的应收金额
            BigDecimal totalPriceSum = getTotalInvoicePrice(vo.getOrderId(), foreignKeyFieldName);

            // 加上新增的应收金额
            BigDecimal totalPrice = totalPriceSum.add(foreignKeyFieldValue);

            //如果是修改要把减去当前这条数据之前的金额
            Long id = vo.getId();
            if (id!=null){
                BigDecimal oldPrice = invoiceMapper.selectById(id).getPrice();
                totalPrice=totalPrice.subtract(oldPrice);
            }

            // 比较总金额与订单金额，如果超出则抛出异常
            if (totalPrice.compareTo(totalMoneyMajorKeyFieldValue) > 0) {
                throw exception(COMPARE_ORDER_INVOICES, totalPriceSum, foreignKeyFieldValue, totalPrice, totalMoneyMajorKeyFieldValue, totalMoneyMajorKeyFieldValue.subtract(totalPriceSum));
            }

        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 计算指定订单的总发票金额。
     *
     * @param orderId             订单 ID
     * @param foreignKeyFieldName 外键字段名
     * @return 总发票金额
     */
    private BigDecimal getTotalInvoicePrice(Long orderId, String foreignKeyFieldName) {
        // 创建一个 LambdaQueryWrapper 对象
        LambdaQueryWrapper<InvoiceDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(InvoiceDO::getOrderId, orderId) // 设置订单 ID 条件
                .ne(InvoiceDO::getAuditStatus, 3); // 设置审核状态不为已驳回的数据

        // 执行查询
        List<InvoiceDO> list = invoiceMapper.selectList(InvoiceDO::getOrderId, orderId);
        return list.stream().map(invoiceDO -> {
            try {
                return getFieldValue(InvoiceDO.class, invoiceDO, foreignKeyFieldName);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
                return BigDecimal.ZERO; // 返回零值以避免异常中断流
            }
        }).reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}
